package zk

import (
	"doveclient/config"
	"errors"
	"fmt"
	"reflect"
	"time"

	"github.com/samuel/go-zookeeper/zk"
)

var storage *Storage

type Storage struct {
	Conn *Conn
}

type Conn struct {
	zkConn *zk.Conn
}

func (conn *Conn) GetW(path string) ([]byte, *zk.Stat, <-chan zk.Event, error) {
	return conn.zkConn.GetW(path)
}

func (conn *Conn) Get(path string) ([]byte, *zk.Stat, error) {
	return conn.zkConn.Get(path)
}

func (conn *Conn) Create(path string, data []byte, flags int32, acl []zk.ACL) (string, error) {
	return conn.zkConn.Create(path, data, flags, acl)
}

func (conn *Conn) Set(path string, data []byte, version int32) (*zk.Stat, error) {
	return conn.zkConn.Set(path, data, version)
}

func (conn *Conn) ExistsW(path string) (bool, *zk.Stat, <-chan zk.Event, error) {
	return conn.zkConn.ExistsW(path)
}

func (conn *Conn) Exists(path string) (bool, *zk.Stat, error) {
	return conn.zkConn.Exists(path)
}

func (conn *Conn) Close() {
	conn.zkConn.Close()
}

func (conn *Conn) Children(path string) ([]string, *zk.Stat, error) {
	return conn.zkConn.Children(path)
}

func (conn *Conn) ChildrenW(path string) ([]string, *zk.Stat, <-chan zk.Event, error) {
	return conn.zkConn.ChildrenW(path)
}

func (conn *Conn) State() zk.State {
	return conn.zkConn.State()
}

// 获取一个连接单例
func GetConn() (*Storage, error) {
	if storage != nil {
		return storage, nil
	}
	storage, _, err := CreateConn()
	return storage, err
}

func CreateConn() (*Storage, <-chan zk.Event, error) {
	defEnv := config.GetConfig().ENV
	zkHosts := config.GetZkConfig()["hosts"].(map[string][]string)
	if zkHosts[defEnv] == nil {
		return nil, nil, errors.New(fmt.Sprintf("Defined ENV(%s) is not valid, it must one of %v", defEnv, reflect.ValueOf(zkHosts).MapKeys()))
	}
	var zkConn *zk.Conn
	var eCh <-chan zk.Event
	var err error
	zkConn, eCh, err = zk.Connect(zkHosts[defEnv], time.Second*1)
	var storage Storage
	if err == nil {
		storage = Storage{Conn: &Conn{zkConn: zkConn}}

	}
	return &storage, eCh, err
}

func GetOneHost() string {
	defEnv := config.GetConfig().ENV
	zkHosts := config.GetZkConfig()["hosts"].(map[string][]string)
	return zkHosts[defEnv][0]
}
